package com.soft.mainsite.common.upload;

import com.soft.mainsite.common.constant.CmsConst;
import com.soft.mainsite.common.exception.ApiException;
import com.soft.mainsite.common.upload.bean.UploadBean;
import com.soft.mainsite.common.utils.ControllerUtil;
import com.soft.mainsite.common.utils.PathUtil;
import com.soft.mainsite.module.web.system.service.AttachmentService;
import com.soft.mainsite.module.web.system.vo.UserVo;
import com.soft.mainsite.mybatis.model.TSysAttachment;
import jodd.datetime.JDateTime;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.UUID;

import static org.apache.xerces.impl.dv.util.HexBin.decode;


/**
 * Description:
 *
 * @author Jin
 * @create 2017-07-19
 */
@Component
@Slf4j
@Scope("prototype")
public class UploadComponent {

    @Autowired
    private AttachmentService attachmentService;

    @Value("${enable.virtual.path}")
    String enableVirtualPath;

    @Value("${windows.file.upload.path}")
    String windowsUploadPath;

    @Value("${linux.file.upload.path}")
    String linuxUploadPath;

    @Value("${enable.file.upload.full.path}")
    private String enableFullPath;

    @Value("${system.site.static.resourcesPath.path}")
    private String resourcesPath;


    public UploadBean uploadFile(MultipartFile multipartFile, HttpServletRequest request) {
        TSysAttachment attachment = new TSysAttachment();
        // 获取用户会话
        UserVo userVo = (UserVo) request.getSession().getAttribute(CmsConst.SITE_USER_SESSION_KEY);
        if (userVo != null) {
            attachment.setUserId(userVo.getUserId().toString());
            attachment.setUsername(userVo.getUsername());
        }
        attachment.setUploadDate(new Date());
        attachment.setUploadIp(ControllerUtil.getRemoteAddress(request));
        attachment.setFileSize(Float.valueOf(multipartFile.getSize()) / 1024);
        attachment.setFileExtname(multipartFile.getContentType());
        attachment.setFileKey(UUID.randomUUID().toString().replace("-", ""));
        attachment.setOriginalFilename(multipartFile.getOriginalFilename());
        // 创建uploadBean
        UploadBean result = new UploadBean();
        String fileType = this.getFileType(attachment.getOriginalFilename());
        String fileName = this.getFileName(fileType);
        String newName = this.getNewFileName(fileName);

        if (!multipartFile.isEmpty()) {
            File file = new File(this.getUploadPath() + newName);
            // 如果不存在就创建
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }

            try {
                // 先尝试压缩并保存图片
                if(CmsConst.IMAGE_GIF.equals(fileType)){
                    multipartFile.transferTo(file);
                }else{
                    Thumbnails.of(multipartFile.getInputStream()).scale(1f).outputQuality(0.25f).toFile(file);
                }
            } catch (IOException e) {
                try {
                    // 失败了再用springmvc自带的方式
                    multipartFile.transferTo(file);
                } catch (IOException e1) {
                    log.error("图片上传失败", e);
                }
            }

            try {
                attachment.setFilePath(newName);
                attachment.setFileName(fileName);
                if (Boolean.parseBoolean(enableFullPath)) {
                    String imgPath = attachment.getFilePath().replaceAll("\\\\", "/");
                    result.setFileUrl(imgPath);
                } else {
                    result.setFileUrl("/res/" + attachment.getFileKey() + "." + fileType);
                }
                attachmentService.save(attachment);
            } catch (Exception e) {
                throw new ApiException(e.getMessage());
            }

            return result;
        } else {
            throw new ApiException("上传文件不能为空！");
        }
    }

    public String getUploadPath() {
        String os = System.getProperty("os.name");
        String uploadPath = "true".equals(enableVirtualPath)
                ? (os.toLowerCase().startsWith("win")
                ? windowsUploadPath
                : linuxUploadPath)
                : PathUtil.getRootClassPath() + File.separator + "static";
        return uploadPath;
    }

    public Charset getCharset() {
        String os = System.getProperty("os.name");
        Charset charset = os.toLowerCase().startsWith("win")
                ? Charset.forName("gbk")
                : Charset.forName("UTF-8");
        return charset;
    }

    public UploadBean uploadBase64File(String data, HttpServletRequest request) {

        // 创建uploadBean
        UploadBean result = new UploadBean();
        if (!StringUtils.isBlank(data)) {
            TSysAttachment attachment = new TSysAttachment();
            UserVo userVo = (UserVo) request.getSession().getAttribute(CmsConst.SITE_USER_SESSION_KEY);
            if (userVo != null) {
                attachment.setUserId(userVo.getUserId().toString());
                attachment.setUsername(userVo.getUsername());
            }
            attachment.setUploadDate(new Date());
            attachment.setUploadIp(ControllerUtil.getRemoteAddress(request));
            attachment.setFileSize(this.getBase64FileSize(data).floatValue() / 1024);
            if (CmsConst.IMAGE_PNG.equals(getBase64FileType(data))) {
                attachment.setFileExtname("image/png");
            } else if (CmsConst.IMAGE_GIF.equals(getBase64FileType(data))) {
                attachment.setFileExtname("image/gif");
            } else if (CmsConst.IMAGE_JPG.equals(getBase64FileType(data))) {
                attachment.setFileExtname("image/jpeg");
            }
            attachment.setFileKey(UUID.randomUUID().toString().replace("-", ""));
            String fileType = this.getBase64FileType(data);
            String fileName = this.getFileName(fileType);
            String newName = this.getNewFileName(fileName);
            attachment.setOriginalFilename(newName);
            File file = new File(this.getUploadPath() + newName);
            attachment.setFilePath(file.getPath());
            attachment.setFileName(fileName);

            // 如果不存在就创建
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            try {
                this.writeFile(this.base64StrToByte(data), file);
            } catch (Exception e) {
                throw new ApiException(e.getMessage());
            }
            if (Boolean.parseBoolean(enableFullPath)) {
                result.setFileUrl(request.getScheme() + "://" + ControllerUtil.getDomain() + "/res/" + attachment.getFileKey() + "." + fileType);
            } else {
                result.setFileUrl("/res/" + attachment.getFileKey() + "." + fileType);

            }
            attachmentService.save(attachment);
            return result;
        } else {
            throw new ApiException("上传文件不能为空！");
        }
    }

    public String getFileName(String fileType) {
        return UUID.randomUUID().toString().replace("-", "") + "." + fileType;
    }

    public String getZipFileName(String fileName) {
        JDateTime jt = new JDateTime();
        return File.separator + "upload" + File.separator + "ebook" + File.separator + jt.getYear()
                + File.separator + jt.getMonth() + File.separator + jt.getDay() + File.separator + fileName;
    }

    public String getNewFileName(String fileName) {
        JDateTime jt = new JDateTime();
        return File.separator + "upload" + File.separator + jt.getYear()
                + File.separator + jt.getMonth() + File.separator + jt.getDay() + File.separator + fileName;
    }

    public String getFileType(String fileName) {
        String type = fileName.substring(fileName.lastIndexOf(".") + 1);
        return type;
    }

    /***
     * data:,文本数据
     data:text/plain,文本数据
     data:text/html,HTML代码
     data:text/html;base64,base64编码的HTML代码
     data:text/css,CSS代码
     data:text/css;base64,base64编码的CSS代码
     data:text/JavaScript,Javascript代码
     data:text/javascript;base64,base64编码的Javascript代码
     编码的gif图片数据
     编码的png图片数据
     编码的jpeg图片数据
     编码的icon图片数据
     */
    public String getBase64FileType(String data) {
        String fileType = data.split(",")[0];
        System.out.println(fileType);
        log.info("上传文件类型" + fileType);
        if ("data:image/png;base64".equals(fileType)) {
            return "png";
        }
        if ("data:image/gif;base64".equals(fileType)) {
            return "gif";
        }
        if ("data:image/jpeg;base64".equals(fileType)) {
            return "jpeg";
        }
        throw new ApiException("对不起，请上传正确的文件格式[.png,.gif,.jpg]");
    }

    private Integer getBase64FileSize(String data) {
        String str = data.split(",")[1];
        Integer equalIndex = str.indexOf("=");
        if (str.indexOf("=") > 0) {
            str = str.substring(0, equalIndex);
        }
        Integer strLength = str.length();
        return strLength - (strLength / 8) * 2;
    }

    private byte[] base64StrToByte(String data) {
        byte[] b;
        b = decode(data.split(",")[1]);
        for (int i = 0; i < b.length; ++i) {

            // 调整异常数据
            if (b[i] < 0) {
                b[i] += 256;
            }
        }
        return b;
    }


    public String getEbookFileFolder() {
        JDateTime jt = new JDateTime();
        return File.separator + "upload" + File.separator + "ebook" + File.separator + jt.getYear()
                + File.separator + jt.getMonth() + File.separator + jt.getDay();
    }

    private synchronized void writeFile(byte[] bytes, File file) throws Exception {
        BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(file));
        stream.write(bytes);
        stream.close();
    }


    public static void main(String[] args) {
        UploadComponent uploadComponent = new UploadComponent();
        String s = "1502176167115.png";
        System.out.println(s.contains("pngs"));
        uploadComponent.getBase64FileSize("");
    }
}
